#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define SERVPORT 3333 //定义端口号
#define BACKLOG 10 //请求队列中允许的最大请求数
#define MAXDATASIZE 50 //数据长度

int main() {
    struct sockaddr_in server_sockaddr, client_sockaddr;
    int sin_size, recvbytes;
    int sockfd, client_fd; 
    char buf[MAXDATASIZE];
	
	// 1. 创建 server 端的 socket（基于 TCP 传输）i
    if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("创建 server socket 失败");
        exit(1);
    }

    printf("Socket success!,sockfd=%d\n", sockfd);
	
	int on = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

	// 2. 设置 server 端 socket 的地址：IP + PORT
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(SERVPORT);
    server_sockaddr.sin_addr.s_addr = INADDR_ANY;
	
	// 3. 将 socket 和 socket 地址绑定在一起
    if((bind(sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr))) == -1) {
        perror("bind");
        exit(-1);
    }

    printf("bind success!\n");
	
	// 4. 让 server socket 处于监听状态，可以接受客户端的连接
    if(listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    printf("listening ... \n");
	
	for (;;) {	
		// 5. 当客户端的连接请求到达，服务器接受客户端，并返回一个客户端 socket 描述符
    	if((client_fd = accept(sockfd,(struct sockaddr *) &client_sockaddr, &sin_size)) == -1) {
        	perror("accept");
        	exit(1);
    	}

    	printf("accept success!\n");
	
		for (;;) {
			// 6. 从客户端 socket 描述符中读取客户端发送过来的数据
			// 就和从某个文件中读取数据是一样的
    		if((recvbytes = read(client_fd, buf, MAXDATASIZE)) == -1) {
        		perror("recv");
        		exit(1);
    		}
			
			// 收到数据大小为 0，说明收到的是 FIN 终止连接请求
			if (recvbytes == 0) break;		
	
    		printf("received a connection : %s\n", buf);
			// 清空 buf
			memset(buf, 0x00, sizeof(buf));

			// 模拟处理延迟，睡 10 秒
			sleep(10);
		
			write(client_fd, "hello server", 13);
			sleep(2);
			write(client_fd, "hello", 5);

		}
	
		close(client_fd);
	}
	// 7. 关闭服务端 server socket
    close(sockfd);

}
